home *** CD-ROM | disk | FTP | other *** search
/ Acorn RISC PD-CD 1 / Acorn RISC PD-CD 1.iso / utilities / _graphics / graphics / _jpeg / c / egetopt next >
Encoding:
Text File  |  1991-10-28  |  9.4 KB  |  289 lines

  1. /*
  2.  * egetopt.c -- Extended 'getopt'.
  3.  *
  4.  * A while back, a public-domain version of getopt() was posted to the
  5.  * net.  A bit later, a gentleman by the name of Keith Bostic made some
  6.  * enhancements and reposted it.
  7.  *
  8.  * In recent weeks (i.e., early-to-mid 1988) there's been some
  9.  * heated discussion in comp.lang.c about the merits and drawbacks
  10.  * of getopt(), especially with regard to its handling of '?'.
  11.  *
  12.  * In light of this, I have taken Mr. Bostic's public-domain getopt()
  13.  * and have made some changes that I hope will be considered to be
  14.  * improvements.  I call this routine 'egetopt' ("Extended getopt").
  15.  * The default behavior of this routine is the same as that of getopt(),
  16.  * but it has some optional features that make it more useful.  These
  17.  * options are controlled by the settings of some global variables.
  18.  * By not setting any of these extra global variables, you will have
  19.  * the same functionality as getopt(), which should satisfy those
  20.  * purists who believe getopt() is perfect and can never be improved.
  21.  * If, on the other hand, you are someone who isn't satisfied with the
  22.  * status quo, egetopt() may very well give you the added capabilities
  23.  * you want.
  24.  *
  25.  * Look at the enclosed README file for a description of egetopt()'s
  26.  * new features.
  27.  *
  28.  * The code was originally posted to the net as getopt.c by ...
  29.  *
  30.  *      Keith Bostic
  31.  *      ARPA: keith@seismo 
  32.  *      UUCP: seismo!keith
  33.  *
  34.  * Current version: added enhancements and comments, reformatted code.
  35.  *
  36.  *      Lloyd Zusman
  37.  *      Master Byte Software
  38.  *      Los Gatos, California
  39.  *      Internet:       ljz@fx.com
  40.  *      UUCP:           ...!ames!fxgrp!ljz
  41.  *
  42.  *      May, 1988
  43.  */
  44.  
  45. /*
  46.  * If you want, include stdio.h or something where EOF and NULL are defined.
  47.  * However, egetopt() is written so as not to need stdio.h, which should
  48.  * make it significantly smaller on some systems.
  49.  */
  50.  
  51. #ifndef EOF
  52. # define EOF            (-1)
  53. #endif /* ! EOF */
  54.  
  55. #ifndef NULL
  56. # define NULL           (char *)0
  57. #endif /* ! NULL */
  58.  
  59. /*
  60.  * None of these constants are referenced in the executable portion of
  61.  * the code ... their sole purpose is to initialize global variables.
  62.  */
  63. #define BADCH           (int)'?'
  64. #define NEEDSEP         (int)':'
  65. #define MAYBESEP        (int)'\0'
  66. #define ERRFD           2
  67. #define EMSG            ""
  68. #define START           "-"
  69.  
  70. /*
  71.  * Here are all the pertinent global variables.
  72.  */
  73. int opterr = 1;         /* if true, output error message */
  74. int optind = 1;         /* index into parent argv vector */
  75. int optopt;             /* character checked for validity */
  76. int optbad = BADCH;     /* character returned on error */
  77. int optchar = 0;        /* character that begins returned option */
  78. int optneed = NEEDSEP;  /* flag for mandatory argument */
  79. int optmaybe = MAYBESEP;/* flag for optional argument */
  80. int opterrfd = ERRFD;   /* file descriptor for error text */
  81. char *optarg;           /* argument associated with option */
  82. char *optstart = START; /* list of characters that start options */
  83.  
  84.  
  85. /*
  86.  * Macros.
  87.  */
  88.  
  89. /*
  90.  * Conditionally print out an error message and return (depends on the
  91.  * setting of 'opterr' and 'opterrfd').  Note that this version of
  92.  * TELL() doesn't require the existence of stdio.h.
  93.  */
  94. #ifdef old
  95. #define TELL(S) { \
  96.         if (opterr && opterrfd >= 0) { \
  97.                 char option = optopt; \
  98.                 write(opterrfd, *nargv, strlen(*nargv)); \
  99.                 write(opterrfd, (S), strlen(S)); \
  100.                 write(opterrfd, &option, 1); \
  101.                 write(opterrfd, "\n", 1); \
  102.         } \
  103.         return (optbad); \
  104. }
  105. #endif
  106. #define TELL(S) { \
  107.         if ( stderr != NULL ) { \
  108.                 char option = optopt; \
  109.                 write(stderr, *nargv, strlen(*nargv)); \
  110.                 write(stderr, (S), strlen(S)); \
  111.                 write(stderr, &option, 1); \
  112.                 write(stderr, "\n", 1); \
  113.         } \
  114.         return (optbad); \
  115. }
  116.  
  117. /*
  118.  * This works similarly to index() and strchr().  I include it so that you
  119.  * don't need to be concerned as to which one your system has.
  120.  */
  121. static char *
  122. _sindex(string, ch)
  123. char *string;
  124. int ch;
  125. {
  126.         if (string != NULL) {
  127.                 for (; *string != '\0'; ++string) {
  128.                         if (*string == (char)ch) {
  129.                                 return (string);
  130.                         }
  131.                 }
  132.         }
  133.  
  134.         return (NULL);
  135. }
  136.  
  137. /*
  138.  * Here it is:
  139.  */
  140. int
  141. egetopt(nargc, nargv, ostr)
  142. int nargc;
  143. char **nargv;
  144. char *ostr;
  145. {
  146.         static char *place = EMSG;      /* option letter processing */
  147.         register char *oli;             /* option letter list index */
  148.         register char *osi = NULL;      /* option start list index */
  149.  
  150.         if (nargv == (char **)NULL) {
  151.                 return (EOF);
  152.         }
  153.  
  154.         if (nargc <= optind || nargv[optind] == NULL) {
  155.                 return (EOF);
  156.         }
  157.  
  158.         if (place == NULL) {
  159.                 place = EMSG;
  160.         }
  161.  
  162.         /*
  163.          * Update scanning pointer.
  164.          */
  165.         if (*place == '\0') {
  166.                 place = nargv[optind];
  167.                 if (place == NULL) {
  168.                         return (EOF);
  169.                 }
  170.                 osi = _sindex(optstart, *place);
  171.                 if (osi != NULL) {
  172.                         optchar = (int)*osi;
  173.                 }
  174.                 if (optind >= nargc || osi == NULL || *++place == '\0') {
  175.                         return (EOF);
  176.                 }
  177.  
  178.                 /*
  179.                  * Two adjacent, identical flag characters were found.
  180.                  * This takes care of "--", for example.
  181.                  */
  182.                 if (*place == place[-1]) {
  183.                         ++optind;
  184.                         return (EOF);
  185.                 }
  186.         }
  187.  
  188.         /*
  189.          * If the option is a separator or the option isn't in the list,
  190.          * we've got an error.
  191.          */
  192.         optopt = (int)*place++;
  193.         oli = _sindex(ostr, optopt);
  194.         if (optopt == optneed || optopt == optmaybe || oli == NULL) {
  195.                 /*
  196.                  * If we're at the end of the current argument, bump the
  197.                  * argument index.
  198.                  */
  199.                 if (*place == '\0') {
  200.                         ++optind;
  201.                 }
  202.                 TELL(": illegal option -- ");   /* byebye */
  203.         }
  204.  
  205.         /*
  206.          * If there is no argument indicator, then we don't even try to
  207.          * return an argument.
  208.          */
  209.         ++oli;
  210.         if (*oli == '\0' || (*oli != optneed && *oli != optmaybe)) {
  211.                 /*
  212.                  * If we're at the end of the current argument, bump the
  213.                  * argument index.
  214.                  */
  215.                 if (*place == '\0') {
  216.                         ++optind;
  217.                 }
  218.                 optarg = NULL;
  219.         }
  220.         /*
  221.          * If we're here, there's an argument indicator.  It's handled
  222.          * differently depending on whether it's a mandatory or an
  223.          * optional argument.
  224.          */
  225.         else {
  226.                 /*
  227.                  * If there's no white space, use the rest of the
  228.                  * string as the argument.  In this case, it doesn't
  229.                  * matter if the argument is mandatory or optional.
  230.                  */
  231.                 if (*place != '\0') {
  232.                         optarg = place;
  233.                 }
  234.                 /*
  235.                  * If we're here, there's whitespace after the option.
  236.                  *
  237.                  * Is it a mandatory argument?  If so, return the
  238.                  * next command-line argument if there is one.
  239.                  */
  240.                 else if (*oli == optneed) {
  241.                         /*
  242.                          * If we're at the end of the argument list, there
  243.                          * isn't an argument and hence we have an error.
  244.                          * Otherwise, make 'optarg' point to the argument.
  245.                          */
  246.                         if (nargc <= ++optind) {
  247.                                 place = EMSG;
  248.                                 TELL(": option requires an argument -- ");
  249.                         }
  250.                         else {
  251.                                 optarg = nargv[optind];
  252.                         }
  253.                 }
  254.                 /*
  255.                  * If we're here it must have been an optional argument.
  256.                  */
  257.                 else {
  258.                         if (nargc <= ++optind) {
  259.                                 place = EMSG;
  260.                                 optarg = NULL;
  261.                         }
  262.                         else {
  263.                                 optarg = nargv[optind];
  264.                                 if (optarg == NULL) {
  265.                                         place = EMSG;
  266.                                 }
  267.                                 /*
  268.                                  * If the next item begins with a flag
  269.                                  * character, we treat it like a new
  270.                                  * argument.  This is accomplished by
  271.                                  * decrementing 'optind' and returning
  272.                                  * a null argument.
  273.                                  */
  274.                                 else if (_sindex(optstart, *optarg) != NULL) {
  275.                                         --optind;
  276.                                         optarg = NULL;
  277.                                 }
  278.                         }
  279.                 }
  280.                 place = EMSG;
  281.                 ++optind;
  282.         }
  283.  
  284.         /*
  285.          * Return option letter.
  286.          */
  287.         return (optopt);
  288. }
  289.